package com.lx.idgenerator.autoconfigure.redis;

import org.springframework.boot.context.properties.ConfigurationProperties;

import java.time.Duration;
import java.util.List;


@ConfigurationProperties(
  prefix = "id.gen.segment.redis"
)
public class RedisProperties {


  private String mode = "standalone";

  /**
   * Database index used by the connection factory.
   */
  private int database = 0;

  /**
   * Connection URL. Overrides host, port, and password. User is ignored. Example:
   * redis://user:password@example.com:6379
   */
  private String url;

  /**
   * Redis server host.
   */
  private String host = "localhost";

  /**
   * Login password of the redis server.
   */
  private String password;

  /**
   * Redis server port.
   */
  private int port = 6379;

  /**
   * Whether to enable SSL support.
   */
  private boolean ssl;

  /**
   * Connection timeout.
   */
  private Duration timeout;

  /**
   * Client name to be set on connections with CLIENT SETNAME.
   */
  private String clientName;

  private Sentinel sentinel;

  private Cluster cluster;

  private final Jedis jedis = new Jedis();

  private final Lettuce lettuce = new Lettuce();

  public int getDatabase() {
    return this.database;
  }

  public void setDatabase(int database) {
    this.database = database;
  }

  public String getUrl() {
    return this.url;
  }

  public void setUrl(String url) {
    this.url = url;
  }

  public String getHost() {
    return this.host;
  }

  public void setHost(String host) {
    this.host = host;
  }

  public String getPassword() {
    return this.password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public int getPort() {
    return this.port;
  }

  public void setPort(int port) {
    this.port = port;
  }

  public boolean isSsl() {
    return this.ssl;
  }

  public void setSsl(boolean ssl) {
    this.ssl = ssl;
  }

  public void setTimeout(Duration timeout) {
    this.timeout = timeout;
  }

  public Duration getTimeout() {
    return this.timeout;
  }

  public String getClientName() {
    return this.clientName;
  }

  public void setClientName(String clientName) {
    this.clientName = clientName;
  }

  public Sentinel getSentinel() {
    return this.sentinel;
  }

  public void setSentinel(Sentinel sentinel) {
    this.sentinel = sentinel;
  }

  public Cluster getCluster() {
    return this.cluster;
  }

  public void setCluster(Cluster cluster) {
    this.cluster = cluster;
  }

  public Jedis getJedis() {
    return this.jedis;
  }

  public Lettuce getLettuce() {
    return this.lettuce;
  }

  public String getMode() {
    return mode;
  }

  public void setMode(String mode) {
    this.mode = mode;
  }

  /**
   * Pool properties.
   */
  public static class Pool {

    /**
     * Maximum number of "idle" connections in the pool. Use a negative value to
     * indicate an unlimited number of idle connections.
     */
    private int maxIdle = 8;

    /**
     * Target for the minimum number of idle connections to maintain in the pool. This
     * setting only has an effect if both it and time between eviction runs are
     * positive.
     */
    private int minIdle = 0;

    /**
     * Maximum number of connections that can be allocated by the pool at a given
     * time. Use a negative value for no limit.
     */
    private int maxActive = 8;

    /**
     * Maximum amount of time a connection allocation should block before throwing an
     * exception when the pool is exhausted. Use a negative value to block
     * indefinitely.
     */
    private Duration maxWait = Duration.ofMillis(-1);

    /**
     * Time between runs of the idle object evictor thread. When positive, the idle
     * object evictor thread starts, otherwise no idle object eviction is performed.
     */
    private Duration timeBetweenEvictionRuns;

    private int maxTotal = 8;

    private long maxWaitMillis = -1L;


    private boolean testOnCreate = false;

    private boolean testOnBorrow = false;

    private boolean testOnReturn = false;

    public int getMaxIdle() {
      return this.maxIdle;
    }

    public void setMaxIdle(int maxIdle) {
      this.maxIdle = maxIdle;
    }

    public int getMinIdle() {
      return this.minIdle;
    }

    public void setMinIdle(int minIdle) {
      this.minIdle = minIdle;
    }

    public int getMaxActive() {
      return this.maxActive;
    }

    public void setMaxActive(int maxActive) {
      this.maxActive = maxActive;
    }

    public Duration getMaxWait() {
      return this.maxWait;
    }

    public void setMaxWait(Duration maxWait) {
      this.maxWait = maxWait;
    }

    public Duration getTimeBetweenEvictionRuns() {
      return this.timeBetweenEvictionRuns;
    }

    public void setTimeBetweenEvictionRuns(Duration timeBetweenEvictionRuns) {
      this.timeBetweenEvictionRuns = timeBetweenEvictionRuns;
    }

    public int getMaxTotal() {
      return maxTotal;
    }

    public void setMaxTotal(int maxTotal) {
      this.maxTotal = maxTotal;
    }

    public long getMaxWaitMillis() {
      return maxWaitMillis;
    }

    public void setMaxWaitMillis(long maxWaitMillis) {
      this.maxWaitMillis = maxWaitMillis;
    }

    public boolean isTestOnCreate() {
      return testOnCreate;
    }

    public void setTestOnCreate(boolean testOnCreate) {
      this.testOnCreate = testOnCreate;
    }

    public boolean isTestOnBorrow() {
      return testOnBorrow;
    }

    public void setTestOnBorrow(boolean testOnBorrow) {
      this.testOnBorrow = testOnBorrow;
    }

    public boolean isTestOnReturn() {
      return testOnReturn;
    }

    public void setTestOnReturn(boolean testOnReturn) {
      this.testOnReturn = testOnReturn;
    }
  }

  /**
   * Cluster properties.
   */
  public static class Cluster {

    /**
     * Comma-separated list of "host:port" pairs to bootstrap from. This represents an
     * "initial" list of cluster nodes and is required to have at least one entry.
     */
    private List<String> nodes;

    /**
     * Maximum number of redirects to follow when executing commands across the
     * cluster.
     */
    private Integer maxRedirects = 3;

    private String password;

    public List<String> getNodes() {
      return this.nodes;
    }

    public void setNodes(List<String> nodes) {
      this.nodes = nodes;
    }

    public Integer getMaxRedirects() {
      return this.maxRedirects;
    }

    public void setMaxRedirects(Integer maxRedirects) {
      this.maxRedirects = maxRedirects;
    }


    public String getPassword() {
      return password;
    }

    public void setPassword(String password) {
      this.password = password;
    }
  }

  /**
   * Redis sentinel properties.
   */
  public static class Sentinel {

    /**
     * Name of the Redis server.
     */
    private String master;

    /**
     * Comma-separated list of "host:port" pairs.
     */
    private List<String> nodes;

    /**
     * Password for authenticating with sentinel(s).
     */
    private String password;

    public String getMaster() {
      return this.master;
    }

    public void setMaster(String master) {
      this.master = master;
    }

    public List<String> getNodes() {
      return this.nodes;
    }

    public void setNodes(List<String> nodes) {
      this.nodes = nodes;
    }

    public String getPassword() {
      return this.password;
    }

    public void setPassword(String password) {
      this.password = password;
    }

  }

  /**
   * Jedis client properties.
   */
  public static class Jedis {

    private String clientName = "client";

    private Boolean usePooling = false;

    private int connectTimeout = 2000;

    private int readTimeout = 2000;




    /**
     * Jedis pool configuration.
     */
    private Pool pool;

    public String getClientName() {
      return clientName;
    }

    public void setClientName(String clientName) {
      this.clientName = clientName;
    }

    public Boolean getUsePooling() {
      return usePooling;
    }

    public void setUsePooling(Boolean usePooling) {
      this.usePooling = usePooling;
    }

    public Pool getPool() {
      return this.pool;
    }

    public void setPool(Pool pool) {
      this.pool = pool;
    }

    public int getConnectTimeout() {
      return connectTimeout;
    }

    public void setConnectTimeout(int connectTimeout) {
      this.connectTimeout = connectTimeout;
    }

    public int getReadTimeout() {
      return readTimeout;
    }

    public void setReadTimeout(int readTimeout) {
      this.readTimeout = readTimeout;
    }
  }

  /**
   * Lettuce client properties.
   */
  public static class Lettuce {

    /**
     * Shutdown timeout.
     */
    private Duration shutdownTimeout = Duration.ofMillis(100);

    /**
     * Lettuce pool configuration.
     */
    private Pool pool;

    private final Cluster cluster = new Cluster();

    public Duration getShutdownTimeout() {
      return this.shutdownTimeout;
    }

    public void setShutdownTimeout(Duration shutdownTimeout) {
      this.shutdownTimeout = shutdownTimeout;
    }

    public Pool getPool() {
      return this.pool;
    }

    public void setPool(Pool pool) {
      this.pool = pool;
    }

    public Cluster getCluster() {
      return this.cluster;
    }

    public static class Cluster {

      private final Refresh refresh = new Refresh();

      public Refresh getRefresh() {
        return this.refresh;
      }

      public static class Refresh {

        /**
         * Cluster topology refresh period.
         */
        private Duration period;

        /**
         * Whether adaptive topology refreshing using all available refresh
         * triggers should be used.
         */
        private boolean adaptive;

        public Duration getPeriod() {
          return this.period;
        }

        public void setPeriod(Duration period) {
          this.period = period;
        }

        public boolean isAdaptive() {
          return this.adaptive;
        }

        public void setAdaptive(boolean adaptive) {
          this.adaptive = adaptive;
        }

      }

    }

  }


}
